
#include "voice_common.h"

#if (VOICE_OUTPUT_APPEND_FRAMES > 0)
static const uint8_t sc_voice_output_append_frames_data[] = {
	0x0f, 0x46, 0x9d, 0x66, 0x00, 0x01, 0x9c, 0xe7, 
	0x39, 0xce, 0x73, 0x27, 0x6c, 0x00, 0x00, 0x0f,
	0x0f, 0x46, 0x93, 0xb4, 0xed, 0x49, 0x9c, 0xe5,
	0x18, 0xc4, 0xeb, 0x27, 0x6c, 0x05, 0x1d, 0x2f
};
void voice_output_decode_append_frames(voice_output_s *output)
{
	if (output->meta_id_index == output->combined_attr->meta_nums) {
		output->meta_data = &sc_voice_output_append_frames_data[0];
		output->meta_left_frame_nums = VOICE_OUTPUT_APPEND_FRAMES;
	}
}
#endif

#if GKT_VOICE_OUTPUT_VOLUME_DISABLE
#define voice_output_decode_volume_adjust(output, sp_data, sp_nums)	\
	do {	\
		gkt_unused(output);	\
		gkt_unused(sp_data);	\
		gkt_unused(sp_nums);	\
	} while (0)
#else

#ifdef GKT_CONFIG_VOICE_OUTPUT_VOLUME_ATTRS
static const voice_output_volume_attr_s sc_voice_output_volume_attrs[] = 
	{ GKT_CONFIG_VOICE_OUTPUT_VOLUME_ATTRS };
#else
static const int16_t sc_voice_output_volume_divisors[] = { 1, 2, 4 };
#endif
static void voice_output_decode_volume_adjust(voice_output_s *output,
				int16_t *sp_data, uint32_t sp_nums)
{
#ifdef GKT_CONFIG_VOICE_OUTPUT_VOLUME_ATTRS
	const voice_output_volume_attr_s *c_amp_attr;
	uint32_t sp_index;
	int32_t sp_value, sp_value_orig;

	c_amp_attr = &sc_voice_output_volume_attrs[output->volume];
	if ((c_amp_attr->multiplier > 0)
		&& (c_amp_attr->divisor > 0)
		&& (c_amp_attr->multiplier < c_amp_attr->divisor)) 
	{
		for (sp_index = 0; sp_index < sp_nums; sp_index++) {
			sp_value_orig = (int32_t)sp_data[sp_index];
			sp_value = (int32_t)sp_data[sp_index];
			sp_value = (sp_value * c_amp_attr->multiplier) / c_amp_attr->divisor;
			if (((sp_value_orig < 0) && (sp_value > 0))
				|| ((sp_value_orig > 0) && (sp_value < 0)))
			{
				gkt_printf("amplitude: overfolw - %d @ %d\n", sp_value_orig, sp_value);
			}
			sp_data[sp_index] = (int16_t)sp_value;
		}
	}
#else
	uint32_t sp_index;
	int16_t divisor;

	divisor = sc_voice_output_volume_divisors[output->volume];
	if ((divisor > 0) && (divisor != 1)) {
		for (sp_index = 0; sp_index < sp_nums; sp_index++)
			sp_data[sp_index] /= divisor;
	}
#endif
}
#endif

int voice_output_decode_blocks(voice_output_s *output, 
				uint32_t block_nums)
{
	uint32_t frame_nums;
	uint8_t *block_buffer;
	uint32_t block_offset, size;

	gkt_trace("decode_blocks:blk(%u-%u), frames(%u-%u)\n", 
		output->block_index, block_nums, 
		output->meta_left_frame_nums, 
		output->total_left_frame_nums);

#if (VOICE_OUTPUT_DEC_TAIL_JOINT_BYTES > 0)
	if (!output->total_left_frame_nums
		&& (output->block_index > 0)
		&& !(output->block_index % VOICE_OUTPUT_DEC_BLOCK_NUMS)) 
	{
		uint8_t *move_from, *move_to;

		output->block_index = 0;
		move_to = output->dec_buffer + VOICE_OUTPUT_DEC_HEAD_CUTOFF_BYTES;
		move_from = move_to + VOICE_OUTPUT_DEC_BUFFER_SIZE;
		memcpy(move_to, move_from, VOICE_OUTPUT_DEC_TAIL_JOINT_BYTES);

		return GKT_SUCCESS;
	}
#endif

	while ((output->total_left_frame_nums > 0) && block_nums--) {
		if (output->block_index % VOICE_OUTPUT_DEC_BLOCK_NUMS) {
			block_offset = (output->block_index % VOICE_OUTPUT_DEC_BLOCK_NUMS) * VOICE_OUTPUT_DEC_BLOCK_BYTES;
			block_offset += VOICE_OUTPUT_DEC_BUFFER_APPEND_BYTES;
			frame_nums = VOICE_OUTPUT_DEC_BLOCK_FRAMES;
		}
		else {
			if (output->block_index > 0) {
#if (VOICE_OUTPUT_DEC_MIDD_JOINT_BYTES > 0)
				uint8_t *move_from, *move_to;

				move_to = output->dec_buffer + VOICE_OUTPUT_DEC_HEAD_CUTOFF_BYTES;
				move_from = move_to + VOICE_OUTPUT_DEC_BUFFER_SIZE;
				memcpy(move_to, move_from, VOICE_OUTPUT_DEC_MIDD_JOINT_BYTES);
#endif
				block_offset = VOICE_OUTPUT_DEC_BUFFER_APPEND_BYTES;
				frame_nums = VOICE_OUTPUT_DEC_BLOCK_FRAMES;
			}
			else {
				block_offset = 0;
				frame_nums = VOICE_OUTPUT_DEC_BLOCK_FRAMES + VOICE_OUTPUT_DEC_BUFFER_APPEND_FRAMES;
			}
		}
		if (frame_nums > output->total_left_frame_nums)
			frame_nums = output->total_left_frame_nums;
		block_buffer = output->dec_buffer + block_offset;

		gkt_trace("decode_blocks: bi(%u), fn(%u), bb(0x%x)\n", 
			output->block_index, frame_nums, (uint32_t)block_buffer);

		while (output->meta_left_frame_nums <= frame_nums) {
			size = gkt_voice_decode(output->meta_left_frame_nums, 
							output->meta_data, block_buffer);
			if (!size)
				return GKT_EDECODE;
			voice_output_decode_volume_adjust(output, (int16_t *)block_buffer,
				output->meta_left_frame_nums * GKT_VOICE_DEC_OUTPUT_FRAME_SIZE);

			frame_nums -= output->meta_left_frame_nums;
			output->total_left_frame_nums -= output->meta_left_frame_nums;
			block_buffer += VOICE_OUTPUT_DEC_FRAME_BYTES * output->meta_left_frame_nums;
			output->meta_left_frame_nums = 0;

			if (frame_nums > 0)
				voice_output_next_meta(output);
			else
				goto next_block;
		}

		size = gkt_voice_decode(frame_nums, output->meta_data, block_buffer);
		if (!size)
			return GKT_EDECODE;
		voice_output_decode_volume_adjust(output, (int16_t *)block_buffer,
				frame_nums * GKT_VOICE_DEC_OUTPUT_FRAME_SIZE);

		output->meta_data += size;
		output->meta_left_frame_nums -= frame_nums;
		output->total_left_frame_nums -= frame_nums;

next_block:
		output->block_index++;
		if (!output->meta_left_frame_nums)
			voice_output_next_meta(output);
	}

	return GKT_SUCCESS;
}

